/*
 * eq.h - 3-band equalizer GUI
 *
 * Copyright (C) 2010-2011 Serge Begger
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "mixer.h"
#include "ui_mixer.h"
#include "QDebug"

mixer::mixer(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::mixer)
{
    ui->setupUi(this);

    mapper = new QSignalMapper(this);
    connect( mapper, SIGNAL(mapped(QString)), this, SLOT(valueStep(QString)) );

    EQCreateSliders();
    EQLinkButtons();
    EQsetPresetValue();
    settings = new QSettings("carpc", "mixer", this);
    settings->setPath(QSettings::IniFormat,QSettings::UserScope,"carpc");
    //eq
    int currIndex = settings->value("preset").toInt();
    ui->presetComboBox->setCurrentIndex(currIndex);
    //mixer
    gst_mixer = 0;
    initMixer();
    MixCreateSliders();
    MixLinkButtons();
    indexMaster = -1;
    oldMasterValue = 0;
    newMasterValue = 0;

    int currSpVolume = settings->value("speechVolume").toInt();
    if (currSpVolume == 0)
        currSpVolume = 60;
   mixSliderSp->setValue(currSpVolume);

   int currHFVolume = settings->value("handsFVolume").toInt();
   if (currHFVolume == 0)
       currHFVolume = 20;
   mixSliderHF->setValue(currSpVolume);
}

mixer::~mixer()
{
    delete ui;
}

void mixer::initMixer() {
    gst_init(0,0);
    const GList *tracks;

    gst_mixer = gst_element_factory_make ("alsamixer", "mixer");
    if (gst_mixer == NULL) {
        return;
    }

    //g_object_set(G_OBJECT(gst_mixer), "device", "hw:1", NULL);
    //g_object_set(G_OBJECT(gst_mixer), "device", "surround51", NULL);
    gst_element_set_state (gst_mixer, GST_STATE_READY);

    tracks = gst_mixer_list_tracks (GST_MIXER(gst_mixer));

     while (tracks != NULL) {
        GstMixerTrack *track = GST_MIXER_TRACK (tracks->data);

        GstMixerTrackFlags flags;
        g_object_get (track, "flags", &flags, NULL);

        gchar *ulabel = NULL;
        g_object_get (track, "untranslated-label", &ulabel, NULL);

        int maxvol = 0;
        g_object_get (track, "max-volume", &maxvol, NULL);

        int volume = 0;
        gst_mixer_get_volume(GST_MIXER(gst_mixer),track,&volume);

        int ch = 0;
        g_object_get (track, "num-channels", &ch, NULL);

        if (ch == 0) { //switch
            bool active = false;
            if (GST_MIXER_TRACK_HAS_FLAG(track, GST_MIXER_TRACK_INPUT))
               active = GST_MIXER_TRACK_HAS_FLAG(track,GST_MIXER_TRACK_RECORD);
            else
               active = !GST_MIXER_TRACK_HAS_FLAG(track,GST_MIXER_TRACK_MUTE);

            mixer_sv_element element_sv;
            element_sv.name = ulabel;
            element_sv.track = track;
            element_sv.on_off = active;
            element_sv.visible = true;

            tracks = tracks->next;
            continue;
        }
        mixer_sl_element element;
        element.track = track;
        element.name = ulabel;
        element.max_vol = maxvol;
        element.visible = true;
        element.curr_vol = volume;
        element.num_ch = ch;
        if(GST_MIXER_TRACK_HAS_FLAG(track, GST_MIXER_TRACK_INPUT)) {
            rec_track.append(element);
        } else if (GST_MIXER_TRACK_HAS_FLAG(track, GST_MIXER_TRACK_OUTPUT)) {
            if (element.name.startsWith("Master",Qt::CaseSensitive)
                    || element.name.startsWith("Front",Qt::CaseInsensitive)
                    || element.name.startsWith("Center",Qt::CaseInsensitive)
                    || element.name.startsWith("Rear",Qt::CaseInsensitive)
                    || element.name.startsWith("LFE",Qt::CaseInsensitive)) {                
                pl_track.append(element);
                if (element.name.startsWith("Master",Qt::CaseSensitive))
                    indexMaster = pl_track.count()-1;
            }
        }

        tracks = tracks->next;
     }
}

void mixer::MixCreateSliders()
{
    mixSliderList = new QList<gslider*>;
    QSizePolicy sizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
    sizePolicy.setHorizontalStretch(0);
    sizePolicy.setVerticalStretch(0);
    for (int i = 0; i < pl_track.count(); ++i) {
        frameMS = new QFrame(ui->gridLayoutWidget_2);
        frameMS->setMinimumSize(QSize(80, 220));
        sizePolicy.setHeightForWidth(frameMS->sizePolicy().hasHeightForWidth());
        frameMS->setSizePolicy(sizePolicy);
        ui->gridLayout_2->addWidget(frameMS, 2, 2*i, 1, 1);

        mixSlider = new gslider(frameMS);
        mixSlider->setGeometry(QRect(20, 0, 40 ,220));
        mixSlider->setMaxValue(pl_track.at(i).max_vol);
        mixSlider->show();
        mixSlider->setValue(pl_track.at(i).curr_vol);

        mixSliderList->append(mixSlider);

        QLabel *label = this->findChild<QLabel*>("labelM"+QString::number(i));
        label->setText(pl_track.at(i).name);
    }

    frameMS = new QFrame(ui->gridLayoutWidget_2);
    frameMS->setMinimumSize(QSize(80, 220));
    sizePolicy.setHeightForWidth(frameMS->sizePolicy().hasHeightForWidth());
    frameMS->setSizePolicy(sizePolicy);
    ui->gridLayout_2->addWidget(frameMS, 2, 11, 1, 1);

    mixSliderHF = new gslider(frameMS);
    mixSliderHF->setGeometry(QRect(20, 0, 40 ,220));
    mixSliderHF->show();

    frameMS = new QFrame(ui->gridLayoutWidget_2);
    frameMS->setMinimumSize(QSize(80, 220));
    sizePolicy.setHeightForWidth(frameMS->sizePolicy().hasHeightForWidth());
    frameMS->setSizePolicy(sizePolicy);
    ui->gridLayout_2->addWidget(frameMS, 2, 13, 1, 1);

    mixSliderSp = new gslider(frameMS);
    mixSliderSp->setGeometry(QRect(20, 0, 40 ,220));
    mixSliderSp->show();

    for (int i = pl_track.count(); i < 5; ++i)
    {
        QPushButton *buttonUp = this->findChild<QPushButton *>("pushButMixUp"+QString::number(i));
        QPushButton *buttonDw = this->findChild<QPushButton *>("pushButMixDw"+QString::number(i));
        QLabel *label = this->findChild<QLabel*>("labelM"+QString::number(i));
        buttonUp->hide();
        buttonDw->hide();
        label->hide();
    }
}

void mixer::MixLinkButtons()
{
    for (int i=0; i < pl_track.count(); i++) {
        QPushButton *button = this->findChild<QPushButton *>("pushButMixUp"+QString::number(i));
        mapper->setMapping( button, "pushButMixUp"+QString::number(i) );
        connect( button, SIGNAL(pressed()), mapper, SLOT(map()) );
    }

    for (int i=0; i < pl_track.count(); i++) {
        QPushButton *button = this->findChild<QPushButton *>("pushButMixDw"+QString::number(i));
        mapper->setMapping( button, "pushButMixDw"+QString::number(i) );
        connect( button, SIGNAL(pressed()), mapper, SLOT(map()) );
    }
}

void mixer::setMixValue(int numTr, int value)
{
    if (gst_mixer) {
        mixer_sl_element element = pl_track.at(numTr);
        gint *volumes = g_new (gint, element.num_ch);
        for (int n = 0; n < element.num_ch; n++)
             volumes[n] = value;

        gst_mixer_set_volume(GST_MIXER(gst_mixer), GST_MIXER_TRACK(element.track), volumes);
        g_free (volumes);
    }
}

int mixer::getMixValue(int numTr)
{
    if (gst_mixer) {
        mixer_sl_element element = pl_track.at(numTr);
        gint *volumes = g_new (gint, element.num_ch);
        for (int n = 0; n < element.num_ch; n++)
             volumes[n] = 0;

        gst_mixer_get_volume(GST_MIXER(gst_mixer), GST_MIXER_TRACK(element.track), volumes);
        g_free (volumes);
        return volumes[0];
    }
    return 0;
}

void mixer::valueStep(QString nameButton)
{
    int numSl = nameButton.right(1).toInt();
    bool isEq = false;
    gslider *slider;
    QString typebutton;
    int step;
    if (nameButton.mid(0,9) == "pushButUp" || nameButton.mid(0,9) == "pushButDw") {
        slider = EQSliderList->at(numSl);
        isEq = true;
        typebutton = nameButton.mid(7,2);
        step = 1;
    } else {
        slider = mixSliderList->at(numSl);
        typebutton = nameButton.mid(10,2);
        step = 5;
    }
    if (typebutton == "Up") {
        int currValue = slider->value() + step;
        if (currValue > slider->maximum())
            currValue = slider->maximum();
        slider->setValue(currValue);
    } else if (typebutton == "Dw"){
        int currValue = slider->value() - step;
        if (currValue < slider->minimum())
            currValue = slider->minimum();
        slider->setValue(currValue);
    }
    if (isEq) {
        EQvalueChange(4);
        ui->presetComboBox->setCurrentIndex(4);
    } else {
        setMixValue(numSl,slider->value());
    }
}

int mixer::speechVolume()
{
    return mixSliderSp->value();
}

void mixer::on_pushButSpUp_pressed()
{
    int currValue = mixSliderSp->value() + 5;
    if (currValue > mixSliderSp->maximum())
        currValue = mixSliderSp->maximum();
    mixSliderSp->setValue(currValue);
    settings->setValue("speechVolume",currValue);

}

void mixer::on_pushButSpDw_pressed()
{
    int currValue = mixSliderSp->value() - 5;
    if (currValue < mixSliderSp->minimum())
        currValue = mixSliderSp->minimum();
    mixSliderSp->setValue(currValue);
    settings->setValue("speechVolume",currValue);
}

void mixer::on_pushButHFUp_pressed()
{
    int currValue = mixSliderHF->value() + 5;
    if (currValue > mixSliderHF->maximum())
        currValue = mixSliderHF->maximum();
    mixSliderHF->setValue(currValue);
    settings->setValue("handsFVolume",currValue);
    newMasterValue = currValue;
}

void mixer::on_pushButHFDw_pressed()
{
    int currValue = mixSliderHF->value() - 5;
    if (currValue < mixSliderHF->minimum())
        currValue = mixSliderHF->minimum();
    mixSliderHF->setValue(currValue);
    settings->setValue("handsFVolume",currValue);
    newMasterValue = currValue;
}

void mixer::setHFMasterValue()
{
    if (indexMaster) {
        oldMasterValue = getMixValue(indexMaster);
        setMixValue(indexMaster,newMasterValue);
    }
}

void mixer::retHFMasterValue()
{
    setMixValue(indexMaster,oldMasterValue);
}

void mixer::on_backButton_pressed()
{
    emit hideWidget();
}

void mixer::on_prevButton_pressed()
{
    int currIndex = ui->stackedWidget->currentIndex() - 1;
    if (currIndex < 0)
        currIndex = 0;

    ui->stackedWidget->setCurrentIndex(currIndex);
    if (currIndex == 0) {
        ui->presetComboBox->setVisible(true);
        ui->iconLabel->setText("EQ");
    }

}

void mixer::on_nextButton_pressed() {
    int currIndex = ui->stackedWidget->currentIndex() + 1;
    if (currIndex > 1)
        currIndex = 1;

    ui->stackedWidget->setCurrentIndex(currIndex);
    if (currIndex != 0) {
        ui->presetComboBox->setVisible(false);
        ui->iconLabel->setText("MIX");
    }
}

void mixer::on_presetComboBox_currentIndexChanged(int index)
{
    switch (index) {
    case 0:
            for (int i=0; i < 10; i++) {
                gslider *slider = EQSliderList->at(i);
                slider->setValue(0);
            }
            break;
    case 1:
            for (int i=0; i < 10; i++) {
                gslider *slider = EQSliderList->at(i);
                slider->setValue(rockPreset->at(i));
            }
            break;
    case 2:
            for (int i=0; i < 10; i++) {
                gslider *slider = EQSliderList->at(i);
                slider->setValue(classicPreset->at(i));
            }
            break;
    case 3:
            for (int i=0; i < 10; i++) {
                gslider *slider = EQSliderList->at(i);
                slider->setValue(popPreset->at(i));
            }
            break;
    case 4:
            EQLoadValue();
            break;
    }

    EQvalueChange();
    settings->setValue("preset",index);
}

void mixer::EQLoadValue()
{
    int size = settings->beginReadArray("eqSettings");
    for (int i=0; i < size; i++) {
        settings->setArrayIndex(i);
        gslider *slider = EQSliderList->at(i);
        slider->setValue(settings->value("value").toDouble());
    }
    settings->endArray();
}

void mixer::EQvalueChange(int index)
{
    if (index == 4) {
        settings->beginWriteArray("eqSettings");
        for (int i=0; i < 10; i++) {
            settings->setArrayIndex(i);
            gslider *slider = EQSliderList->at(i);
            settings->setValue("value", slider->value());
        }
        settings->endArray();
    }
    double band[10];
    EQcurValue(band);
    emit EQSliderValue(band);
}

void mixer::EQcurValue(double *band)
{
    for (int i=0; i < 10; i++) {
        gslider *slider = EQSliderList->at(i);
        band[i] =  slider->value();
    }
}

void mixer::EQCreateSliders()
{
    EQSliderList = new QList<gslider*>;
    QSizePolicy sizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
    sizePolicy.setHorizontalStretch(0);
    sizePolicy.setVerticalStretch(0);
    for (int i = 0; i < 10; ++i) {
        frameEQS = new QFrame(ui->gridLayoutWidget);
        frameEQS->setMinimumSize(QSize(60, 240));
        sizePolicy.setHeightForWidth(frameEQS->sizePolicy().hasHeightForWidth());
        frameEQS->setSizePolicy(sizePolicy);
        ui->gridLayout->addWidget(frameEQS, 2, 2*i, 1, 1);

        eqSlider = new gslider(frameEQS);
        eqSlider->setGeometry(QRect(10, 0, 40 ,240));
        eqSlider->setMaxValue(12);
        eqSlider->setMinValue(-12);
        eqSlider->show();
        eqSlider->setValue(0);

        EQSliderList->append(eqSlider);
    }
}

void mixer::EQLinkButtons()
{
    for (int i=0; i < 10; i++) {
        QPushButton *button = this->findChild<QPushButton *>("pushButUp"+QString::number(i));
        mapper->setMapping( button, "pushButUp"+QString::number(i) );
        connect( button, SIGNAL(pressed()), mapper, SLOT(map()) );
    }

    for (int i=0; i < 10; i++) {
        QPushButton *button = this->findChild<QPushButton *>("pushButDw"+QString::number(i));
        mapper->setMapping( button, "pushButDw"+QString::number(i) );
        connect( button, SIGNAL(pressed()), mapper, SLOT(map()) );
    }
}

void mixer::EQsetPresetValue()
{
    rockPreset = new QList<double>;
    rockPreset->append(9.0);
    rockPreset->append(5.0);
    rockPreset->append(2.0);
    rockPreset->append(-3.0);
    rockPreset->append(-8.0);
    rockPreset->append(-4.0);
    rockPreset->append(-1.0);
    rockPreset->append(3.0);
    rockPreset->append(8.0);
    rockPreset->append(12.0);

    classicPreset = new QList<double>;
    for (int i = 0; i < 7; i++) {
        classicPreset->insert(i,0);
    }
    classicPreset->append(-7.0);
    classicPreset->append(-7.0);
    classicPreset->append(-7.0);
    classicPreset->append(-10);

    popPreset = new QList<double>;
    popPreset->append(-2.0);
    popPreset->append(5.0);
    popPreset->append(7.0);
    popPreset->append(8.0);
    popPreset->append(5.0);
    popPreset->append(0.0);
    popPreset->append(-3.0);
    popPreset->append(-3.0);
    popPreset->append(-2.0);
    popPreset->append(-1.0);
}
